//*********************************************
//  This is Geant4 Template
//                                  author:Qian
//
//
// The purpose of this class is to store the simulated data to a given nutple/root
// There are two ways:
// 1. use g4root, G4AnalysisManager, the geant4 ntuple manager to store the data.
// 2. use root, MyAnalysisManager->SimEvent or tree/branch, the root file to store the data.
// either way can work, choose one to fullfill your requirements.

#include "MyAnalysisManager.hh"
#include "MyRootBasedAnalysis.hh"

#include "MyDetectorConstruction.hh"
#include "MyG4BasedAnalysis.hh"
#include "MyRootBasedAnalysis.hh"

#include "G4EventManager.hh"
#include "G4TrackingManager.hh"

#include "Verbose.hh"
#include <algorithm>

//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......

MyAnalysisManager *MyAnalysisManager::fInstance = 0;

//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......

MyAnalysisManager::MyAnalysisManager()
{
    // default using G4AnalysisManager
    //fMyG4BasedAnalysis = new MyG4BasedAnalysis();
    //fMyRootBasedAnalysis = new MyRootBasedAnalysis();
    fMyBasedAnalysis = NULL;
}

//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......

MyAnalysisManager::~MyAnalysisManager()
{
}

//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
void MyAnalysisManager::SetOutputInfo(YAML::Node controlOutput, G4bool ifValid) 
{
    int outputMode = controlOutput["Mode"].as<int>(1);

    switch(outputMode)
    {
        case 1: 
        {
            fMyBasedAnalysis = new MyG4BasedAnalysis();
            break;
        }
        case 2:
        {
            fMyBasedAnalysis = new MyRootBasedAnalysis();
            break;
        }
        default:
        {
            G4cout << "Warning!!! OutputMode " << outputMode << " not found, use default MyG4BasedAnalysis mode." << G4endl;
            fMyBasedAnalysis = new MyG4BasedAnalysis();
        }
    }

    fMyBasedAnalysis->Activated();
    fMyBasedAnalysis->SetFileName(controlOutput["FileName"].as<std::string>("sim.root"));
    fMyBasedAnalysis->SetOutputLevel(controlOutput["Level"].as<int>(1));
    fMyBasedAnalysis->SetValidFlag(ifValid);
}

void MyAnalysisManager::BeginOfRunAction()
{
    if (verbose)
        G4cout << "====>MyAnalysisManager::BeginOfRunAction()" << G4endl;

    fMyBasedAnalysis->BeginOfRunAction();
}

//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......

void MyAnalysisManager::EndOfRunAction()
{
    if (verbose)
        G4cout << "====>MyAnalysisManager::EndOfRunAction()" << G4endl;

    fMyBasedAnalysis->EndOfRunAction();
}

//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......

void MyAnalysisManager::BeginOfEventAction(const G4Event *evt)
{
    if (verbose)
        G4cout << "====>MyAnalysisManager::BeginOfEventAction()" << G4endl;

    fMyBasedAnalysis->BeginOfEventAction(evt);
}

//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......

void MyAnalysisManager::EndOfEventAction(const G4Event *evt)
{
    if (verbose)
        G4cout << "====>MyAnalysisManager::EndOfEventAction()" << G4endl;

    fMyBasedAnalysis->EndOfEventAction(evt);
}

//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
G4ClassificationOfNewTrack MyAnalysisManager::ClassifyNewTrack(const G4Track *aTrack)
{
    return fMyBasedAnalysis->ClassifyNewTrack(aTrack);
    //if (fMyG4BasedAnalysis->IsActivated())
    //    return fMyG4BasedAnalysis->ClassifyNewTrack(aTrack);
    //else
    //    return fMyRootBasedAnalysis->ClassifyNewTrack(aTrack);
}

//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
void MyAnalysisManager::PreTrackingAction(const G4Track *aTrack)
{
    fMyBasedAnalysis->PreTrackingAction(aTrack);
}

//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
void MyAnalysisManager::PostTrackingAction(const G4Track *aTrack)
{
    fMyBasedAnalysis->PostTrackingAction(aTrack);
}

//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
void MyAnalysisManager::SteppingAction(const G4Step *aStep)
{
    fMyBasedAnalysis->SteppingAction(aStep);
}

//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
void MyAnalysisManager::SetG4BasedFileName(G4String fname) { fMyBasedAnalysis->SetFileName(fname); }
void MyAnalysisManager::G4BasedActivated() 
{ 
    if(fMyBasedAnalysis != NULL)
    {
        fMyBasedAnalysis->Deactivated();
        delete fMyBasedAnalysis;
    }
    fMyBasedAnalysis = new MyG4BasedAnalysis();
    fMyBasedAnalysis->Activated(); 
}
void MyAnalysisManager::G4BasedDeactivated()
{ 
    fMyBasedAnalysis->Deactivated(); 
    delete fMyBasedAnalysis;
}

void MyAnalysisManager::SetRootBasedFileName(G4String fname) { fMyBasedAnalysis->SetFileName(fname); }
void MyAnalysisManager::RootBasedActivated() 
{ 
    if(fMyBasedAnalysis != NULL)
    {
        fMyBasedAnalysis->Deactivated();
        delete fMyBasedAnalysis;
    }
    fMyBasedAnalysis = new MyRootBasedAnalysis();
    fMyBasedAnalysis->Activated(); 
}
void MyAnalysisManager::RootBasedDeactivated()
{ 
    fMyBasedAnalysis->Deactivated(); 
    delete fMyBasedAnalysis;
}

void MyAnalysisManager::SetDetectorConstruction(MyDetectorConstruction *det)
{
    fDetector = det;
    fMyBasedAnalysis->SetDetectorConstruction(det);
}

void MyAnalysisManager::SetRunAction(MyRunAction *run)
{
    fRunAction = run;
    fMyBasedAnalysis->SetRunAction(run);
}

void MyAnalysisManager::SetEvtAction(MyEvtAction *evt)
{
    fEvtAction = evt;
    fMyBasedAnalysis->SetEvtAction(evt);
}
